package com.zhangfb95.crosschain.plugin.client.java.fabric2.service.impl;

import com.zhangfb95.crosschain.plugin.client.java.fabric2.infra.data.api.container.ChainApi;
import com.zhangfb95.crosschain.plugin.client.java.fabric2.infra.data.converter.PluginConverter;
import com.zhangfb95.crosschain.plugin.client.java.fabric2.infra.model.api.request.container.GetHeightApiReq;
import com.zhangfb95.crosschain.plugin.client.java.fabric2.infra.model.api.request.container.QueryBlockByNumberApiReq;
import com.zhangfb95.crosschain.plugin.client.java.fabric2.infra.model.api.request.container.QueryByChaincodeApiReq;
import com.zhangfb95.crosschain.plugin.client.java.fabric2.infra.model.api.request.container.QueryInstalledChainCodesApiReq;
import com.zhangfb95.crosschain.plugin.client.java.fabric2.infra.model.api.request.container.QueryTransactionByIDApiReq;
import com.zhangfb95.crosschain.plugin.client.java.fabric2.infra.model.api.request.container.SendApiReq;
import com.zhangfb95.crosschain.plugin.client.java.fabric2.infra.model.api.response.container.QueryBlockByNumberApiRes;
import com.zhangfb95.crosschain.plugin.client.java.fabric2.infra.model.api.response.container.QueryByChaincodeApiRes;
import com.zhangfb95.crosschain.plugin.client.java.fabric2.infra.model.api.response.container.QueryInstalledChainCodesApiRes;
import com.zhangfb95.crosschain.plugin.client.java.fabric2.infra.model.api.response.container.QueryTransactionByIDApiRes;
import com.zhangfb95.crosschain.plugin.client.java.fabric2.infra.model.api.response.container.SendApiRes;
import com.zhangfb95.crosschain.protocol.routerpluginapi.PluginService;
import com.zhangfb95.crosschain.protocol.routerpluginapi.request.QueryPluginReq;
import com.zhangfb95.crosschain.protocol.routerpluginapi.request.SendPluginReq;
import com.zhangfb95.crosschain.protocol.routerpluginapi.response.GetBlockByNumberPluginRes;
import com.zhangfb95.crosschain.protocol.routerpluginapi.response.GetTxByIdPluginRes;
import com.zhangfb95.crosschain.protocol.routerpluginapi.response.QueryPluginRes;
import com.zhangfb95.crosschain.protocol.routerpluginapi.response.SendPluginRes;

import java.util.ArrayList;
import java.util.List;

/**
 * @author zhangfubing
 * @since 2023/12/3
 */
public class JavaFabric2PluginServiceImpl implements PluginService {

    private final boolean enable;
    private final ChainApi chainApi;

    public JavaFabric2PluginServiceImpl(boolean enable, ChainApi chainApi) {
        this.enable = enable;
        this.chainApi = chainApi;
    }

    @Override
    public boolean isEnable() {
        return enable;
    }

    @Override
    public String getChainName() {
        return chainApi.getChainName().fallback().getData().getChainName();
    }

    @Override
    public List<String> listChainPath() {
        // 获取链名称
        String chainName = getChainName();

        // 获取通道和链码信息
        List<String> chainPaths = new ArrayList<>();
        QueryInstalledChainCodesApiReq apiReq = new QueryInstalledChainCodesApiReq();
        QueryInstalledChainCodesApiRes apiRes = chainApi.queryInstalledChainCodes(apiReq).fallback().getData();
        apiRes.getChannel2chainCode2VersionMap().forEach((channelName, chaincode2VersionMap) -> {
            chaincode2VersionMap.forEach((chaincodeName, chaincodeVersion) -> {
                chainPaths.add(chainName + "." + channelName + "." + chaincodeName);
            });
        });

        return chainPaths;
    }

    @Override
    public long getHeight(String chainPath) {
        GetHeightApiReq apiReq = new GetHeightApiReq().setChainPath(chainPath);
        return chainApi.getHeight(apiReq).fallback().getData().getHeight();
    }

    @Override
    public GetBlockByNumberPluginRes getBlockByNumber(String chainPath, Long blockNumber) {
        QueryBlockByNumberApiReq apiReq = new QueryBlockByNumberApiReq()
                .setChainPath(chainPath)
                .setBlockNumber(blockNumber);
        QueryBlockByNumberApiRes apiRes = chainApi.queryBlockByNumber(apiReq).fallback().getData();
        return new GetBlockByNumberPluginRes()
                .setBlockNumber(apiRes.getBlockNumber())
                .setDataHash(apiRes.getDataHash())
                .setBlockHash(apiRes.getBlockHash())
                .setPreviousHash(apiRes.getPreviousHash())
                .setBlockBytes(apiRes.getBlockBytes())
                .setTxIds(apiRes.getTxIds());
    }

    @Override
    public GetTxByIdPluginRes getTxById(String chainPath, String txId) {
        QueryTransactionByIDApiReq apiReq = new QueryTransactionByIDApiReq()
                .setChainPath(chainPath)
                .setTxId(txId);
        QueryTransactionByIDApiRes apiRes = chainApi.queryTransactionByID(apiReq).fallback().getData();
        return new GetTxByIdPluginRes()
                .setTxId(apiRes.getTxId())
                .setTransactionBytes(apiRes.getTransactionBytes());
    }

    @Override
    public QueryPluginRes query(QueryPluginReq req) {
        QueryByChaincodeApiReq apiReq = PluginConverter.INSTANCE.convert(req);
        QueryByChaincodeApiRes apiRes = chainApi.queryByChaincode(apiReq).fallback().getData();
        return PluginConverter.INSTANCE.convert(apiRes);
    }

    @Override
    public SendPluginRes send(SendPluginReq req) {
        SendApiReq apiReq = PluginConverter.INSTANCE.convert(req);
        SendApiRes apiRes = chainApi.send(apiReq).fallback().getData();
        return PluginConverter.INSTANCE.convert(apiRes);
    }
}
